

const store = {
  state: {
    width: 600,
    height: 500,
    x: 5,
    y: 10,

    

    type: 1,
  },
  constant: {
    APPLE_TYPE: 1,
    BANANA_TYPE: 2,
  }
}

const test = [
  // '1 + 1',
  // '(1+2)*(3+4)+(5+6)/(7-8)',
  '(1+2)*(3+4)',
  // '(1*2+3)*(3+4/2)',
  // '(1+2*3)-(3+4*2)',
  '(12+34)*(4-5)',
  '{width} - {height}',
  // '{type} + 1',
  '{x}*2+ {y}',
  // '{width} - 50',
  // `1+(2+(3+(4+(5+6+7))))`,
  `4*(1/2+3)`,
  '(1+2*3)⊙35',
  '5⊙15',
  '7⊙15',
  '1=2',
  '2>1',
  '5>2 & 2>1',
  '{x}^2+{y}',
  '{x}^2+{y} > 30',
  '{type} = {APPLE_TYPE}',
  '{type} = {BANANA_TYPE}',
];

const state = store.state;
const CONSTANT = store.constant;

const notPrimeMap = {
  1: true,
};

for(let i = 2 ; i<1000 ; ++i) {
  for(let j = i * 2 ; !notPrimeMap[i] && j< 1000 ; j+=i) {
    notPrimeMap[j] = true;
  }
}

const operaLevelMap = {
  '=': 0,
  '>': 0,
  '<': 0,
  '&': 0,
  '|': 0,
  '+': 1,
  '-': 1,
  '*': 2,
  '/': 2,
  '⊙': 3,
  '^': 3,
};

const circleHasComputed = (circle1, circle2) => {
  const circle1To2 = Math.sqrt(Math.pow(Math.abs(circle1.x - circle2.x), 2) + Math.pow(Math.abs(circle1.y - circle2.y), 2))
  console.log(circle1To2);
  return circle1To2 + circle2.r <= circle1.r ? 1 : 0;
};

const operaCompute = {
  '=': (num1, num2) => {
    return num1 === num2? 1: 0;
  },
  '>': (num1, num2) => {
    return num1>num2? 1: 0;
  },
  '<': (num1, num2) => {
    return num1<num2? 1: 0;
  },
  '&': (num1, num2) => {
    return num1&num2? 1: 0;
  },
  '|': (num1, num2) => {
    return num1|num2? 1: 0;
  },
  '+': (num1, num2) => {
    return num1+num2;
  },
  '-': (num1, num2) => {
    return num1 - num2;
  },
  '*': (num1, num2) => {
    return num1*num2;
  },
  '/': (num1, num2) => {
    return num1/num2;
  },
  '⊙': (num1, num2) => {
    return !notPrimeMap[num1] && num2 % num1 === 0? 1: 0;
  },
  '^': (num1, num2) => {
    return Math.pow(num1, num2);
  }
}

const handleElement = (expression, i) => {
  if (expression[i] !== '{') {
    return getNumber(expression, i);
  } else {
    return getState(expression, i);
  }
}

const getState = (expression, i) => {
  i += 1;
  const key = [];
  while(expression[i] !== '}') {
    key.push(expression[i]);
    ++i;
  }
  return [state[key.join('')] || CONSTANT[key.join('')] , i];
}

const getNumber = (expression, i) => {
  const nums = [];
  while(Number.isInteger(+expression[i]) || expression[i] === '.') {
    nums.push(expression[i]);
    ++i;
  }
  return [+nums.join(''), i-1];
};

const handleCompute = (num2, num1, sign) => {
  // console.log(sign, num1, num2);
  return operaCompute[sign](num1, num2)
};
/**
 * 中缀表达式转换逆波兰表达式
 * @param {string} expression 
 */
const toReversePolishNotation = (expression) => {
  const elementStack = [];
  const operationStack = [];

  for(let i = 0, len = expression.length ; i<len ; ++i) {
    if (operaLevelMap[expression[i]] !== undefined) {
      // 是运算符
      if (operationStack.length > 0) {
        const topOpera = operationStack.pop();
        if (operaLevelMap[expression[i]] > operaLevelMap[topOpera] || topOpera === '(') {
          operationStack.push(topOpera, expression[i]);
        } else {
          elementStack.push(topOpera);
          operationStack.push(expression[i]);
        }
      } else {
        operationStack.push(expression[i]);
      }
    
    } else if (expression[i] === '(') {
      // 是 (
      operationStack.push('(')
    } else if (expression[i] === ')') {
      // 是 )，往elementStack里塞运算符
      let opera = '';
      while((opera = operationStack.pop()) !== '(') {
        elementStack.push(opera);
      }
    // 忽略
    } else if (expression[i] === ' ') {
      // continue;
    } else {
      // 是 element
      let num = 0;
      [num, i] = handleElement(expression, i);
      elementStack.push(num);
    }
    // console.log('elementStack', elementStack, 'operationStack', operationStack);
  }
  while(operationStack.length > 0) {
    elementStack.push(operationStack.pop());
  }
  return elementStack;
}

/**
 * 
 * @param {Array} reversePolishNotation 上面的elementStack
 */
const computeReversePolishNotation = (reversePolishNotation) => {
  const numberStack = [];

  reversePolishNotation.forEach((element) => {
    if (typeof element === 'number') {
      numberStack.push(element);
    } else {
      numberStack.push(handleCompute(numberStack.pop(), numberStack.pop(), element));
    }
    // console.log(numberStack)
  })
  return numberStack.pop();
}

test.forEach(expression => {
  const reversePolishNotation = toReversePolishNotation(expression);
  console.log('expression', expression, 
    '，reversePolishNotation：', reversePolishNotation, 
    '，result：', expression +' = '+ computeReversePolishNotation(reversePolishNotation));
})


